
#include "core/threads.h"
#include "core/utils.h"
#include "vetest.h"

/***********************************************************************/

struct test_threads_data
{
	int value;
};

void test_threads_thread( void *data )
{
	struct test_threads_data *tdata = (struct test_threads_data*)data;
	tdata->value = 1;
}

void test_threads()
{
	struct test_threads_data data;
	VEThread *thread;

	data.value = 0;
	thread = ve_thread_create( test_threads_thread, &data );
	ve_thread_delete( thread );
	VE_VERIFY( data.value == 1 );
}

/***********************************************************************/

struct test_atomics_data
{
	VEAtomicInt counter;
};

void test_atomics_thread( void *data )
{
	int i;
	struct test_atomics_data *tdata = (struct test_atomics_data*)data;
	for( i = 0; i < 2000000; ++i )
		ve_atomic_inc( &tdata->counter );
}

void test_atomics()
{
	int i;
	struct test_atomics_data data;
	VEThread *thread;

	data.counter = 0;
	thread = ve_thread_create( test_atomics_thread, &data );
	for( i = 0; i < 2000000; ++i )
		ve_atomic_inc( &data.counter );
	ve_thread_delete( thread );
	VE_VERIFY( data.counter == 4000000 );
}

/***********************************************************************/

struct test_spinlock_data
{
	VEAtomicInt guard;
	VEAtomicInt counter;
};

void test_spinlock_thread( void *data )
{
	struct test_spinlock_data *tdata = (struct test_spinlock_data*)data;

	ve_atomic_lock( &tdata->guard );
	VE_VERIFY( !tdata->counter );
	ve_atomic_inc( &tdata->counter );
	ve_sleep( 20 );
	ve_atomic_dec( &tdata->counter );
	ve_atomic_unlock( &tdata->guard );
}

void test_spinlock()
{
	struct test_spinlock_data data;
	VEThread *thread;

	data.guard = 0;
	data.counter = 0;
	thread = ve_thread_create( test_spinlock_thread, &data );

	ve_atomic_lock( &data.guard );
	VE_VERIFY( !data.counter );
	ve_atomic_inc( &data.counter );
	ve_sleep( 20 );
	ve_atomic_dec( &data.counter );
	ve_atomic_unlock( &data.guard );

	ve_thread_delete( thread );
}

/***********************************************************************/

struct test_mutex_data
{
	VEMutex     *guard;
	VEAtomicInt  counter;
};

void test_mutex_thread( void *data )
{
	struct test_mutex_data *tdata = (struct test_mutex_data*)data;

	ve_mutex_lock( tdata->guard );
	VE_VERIFY( !tdata->counter );
	ve_atomic_inc( &tdata->counter );
	ve_sleep( 20 );
	ve_atomic_dec( &tdata->counter );
	ve_mutex_unlock( tdata->guard );
}

void test_mutex()
{
	struct test_mutex_data data;
	VEThread *thread;

	data.guard = ve_mutex_create();
	data.counter = 0;
	thread = ve_thread_create( test_mutex_thread, &data );

	ve_mutex_lock( data.guard );
	VE_VERIFY( !data.counter );
	ve_atomic_inc( &data.counter );
	ve_sleep( 20 );
	ve_atomic_dec( &data.counter );
	ve_mutex_unlock( data.guard );

	ve_thread_delete( thread );
	ve_mutex_delete( data.guard );
}

/***********************************************************************/

struct test_thread_event_data
{
	VEThreadEvent *event;
	volatile int   flag;
};

void test_thread_event_thread( void *data )
{
	struct test_thread_event_data *tdata = (struct test_thread_event_data*)data;

	ve_thread_event_wait( tdata->event );	/* 0 */
	tdata->flag = 1;						/* 21 */

	ve_sleep( 40 );
	ve_thread_event_wait( tdata->event );	/* 60 */
	ve_thread_event_wait( tdata->event );	/* 61 */
	tdata->flag = 2;						/* 81 */
}

void test_thread_event()
{
	struct test_thread_event_data data;
	VEThread *thread;

	data.event = ve_thread_event_create();
	data.flag = 0;
	thread = ve_thread_create( test_thread_event_thread, &data );	/* 0 */

	ve_sleep( 20 );
	VE_VERIFY( data.flag == 0 );									/* 20 */

	ve_thread_event_signal( data.event );							/* 21 */
	ve_sleep( 20 );
	VE_VERIFY( data.flag == 1 );									/* 40 */

	ve_thread_event_signal( data.event );							/* 41 */
	ve_thread_event_signal( data.event );							/* 42 */
	ve_sleep( 40 );
	VE_VERIFY( data.flag == 1 );									/* 80 */

	ve_thread_event_signal( data.event );							/* 81 */
	ve_sleep( 20 );
	VE_VERIFY( data.flag == 2 );									/* 100 */

	ve_thread_delete( thread );
	ve_thread_event_delete( data.event );
}

/***********************************************************************/

int main( int argc, char *argv[] )
{
	test_threads();
	test_atomics();
	test_spinlock();
	test_mutex();
	test_thread_event();

	return 0;
}
